import { ref } from 'vue'
import { useMessage } from './useMessage'

interface RequestOptions {
	showError?: boolean | string
	showSuccess?: boolean | string
	showLoading?: boolean
	pageSize?: number
	onSuccess?: any
	onError?: any
	onFinally?: any
	// 参数别名 配置的值是对应字段传递给接口的
	paramsAlias?: {
		page?: string
		pageSize?: string
	}
	// 返回值别名 使用对应的字段名从接口返回结果取值, 接口返回的字段可能不是组件内使用的字段名
	resultAlias?: {
		list?: string
		total?: string
	}
}

interface RunOptions {
	refresh?: boolean
}

const message = useMessage()

export const useRequest = <T>(
	api: any,
	options: RequestOptions = {
		showError: false,
		showLoading: false,
		showSuccess: false
	}
) => {
	const loading = ref(false)
	const data = ref<null | T>(null)
	const error = ref<any>(null)
	const isFinish = ref(false)
	const isEmpty = ref(false)
	const page = ref(0)
	const pageSize = ref(options.pageSize)
	const total = ref(0)
	const list = ref<T[]>([])
	const run = async (arg: any = null, runOpts: RunOptions = {}) => {
		let loadingInstance
		try {
			loading.value = true
			isFinish.value = false

			if (runOpts.refresh) {
				list.value.length = 0
			}
			isEmpty.value = list.value.length === 0
			error.value = null
			if (options.showLoading) {
				loadingInstance = message.loading()
			}
			let res
			if (Array.isArray(api)) {
				res = await Promise.all(api.map((subApi, index) => subApi(arg[index])))
			} else {
				const params = { ...arg }
				if (options.pageSize) {
					page.value = runOpts.refresh ? 1 : page.value + 1
					params[options.paramsAlias?.page ?? 'page'] = page.value
					params[options.paramsAlias?.pageSize ?? 'pageSize'] = params.pageSize || pageSize.value
				}
				res = await api(params)
			}
			if (options.showSuccess) {
				if (typeof options.showSuccess === 'string') {
					message.success(options.showSuccess)
				} else {
					message.success()
				}
			}
			if (Array.isArray(api)) {
				data.value = res.map((item: any) => item.data)
			} else {
				data.value = res?.data
				const _list = res?.data?.[options?.resultAlias?.list ?? 'list']
				const _total = res?.data?.[options?.resultAlias?.total ?? 'total']
				if (_list) {
					if (runOpts.refresh) {
						list.value = _list
					} else {
						list.value = [...list.value, ..._list]
					}
					isEmpty.value = list.value.length === 0
					isFinish.value = !_total || list.value.length >= _total || !_list.length
					total.value = res.data.total
				} else if (res?.data) {
					isEmpty.value = !data.value
				}
			}
			options.onSuccess && options.onSuccess(data.value)
			return res
		} catch (err: any) {
			error.value = err
			if (options.showError) {
				if (typeof options.showError === 'string') {
					message.error(options.showError)
				} else {
					console.error(err)
					message.error(err)
				}
			}
			options.onError && options.onError(err)
		} finally {
			loading.value = false
			loadingInstance && loadingInstance.destroy()
			options.onFinally && options.onFinally()
		}
	}
	const reset = () => {
		data.value = null
		loading.value = false
		isEmpty.value = false
		isFinish.value = false
		error.value = null
		page.value = 0
		total.value = 0
		list.value = []
	}
	return {
		loading,
		isFinish,
		isEmpty,
		data,
		error,
		page,
		pageSize,
		total,
		list,
		run,
		reset
	}
}
